package cn.buk.qms.service;


import cn.buk.common.JsonResult;
import cn.buk.common.dto.eterm.TprInfoDto;
import cn.buk.common.dto.eterm.TprItemDto;
import cn.buk.common.sc.CommonSearchCriteria;
import cn.buk.common.util.DateUtil;
import cn.buk.common.util.FlightTicketUtil;
import cn.buk.tms.dao.FlightCharterDao;
import cn.buk.tms.dto.TicketSaleDto;
import cn.buk.tms.sc.SearchQinfoCriteria;
import cn.buk.tms.sc.SearchTprCriteria;
import cn.buk.tms.entity.misc.*;
import cn.buk.tms.flight.dto.SubclassInfoDto;
import cn.buk.tms.flight.service.EtermService;
import cn.buk.tms.util.ValidationUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFDataFormat;
import org.apache.poi.ss.usermodel.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileInputStream;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 航班包机信息的相关操作
 *
 * @author yfdia
 * @date 2016-6-13
 */
@Component
public class FlightCharterServiceImpl extends BaseAbstractService implements FlightCharterService {

    private static final Logger logger = LogManager.getLogger(FlightCharterServiceImpl.class);


    @Autowired
    private FlightCharterDao flightCharterDao;

    @Autowired
    private EtermService etermService;

    @Override
    public List<Qinfo> searchQinfo(int enterpriseId, SearchQinfoCriteria sc) {
        return flightCharterDao.searchQinfo(enterpriseId, sc);
    }

    @Override
    public JsonResult reInformQinfo(int enterpriseId, int id) {
        JsonResult jsonResult = new JsonResult();
        jsonResult.setStatus("ER");

        int retCode = flightCharterDao.reInformQinfo(enterpriseId, id);
        if (retCode > 0) {
            jsonResult.setStatus("OK");
        } else {
            jsonResult.setErrcode(retCode);
            jsonResult.setErrmsg("操作失败");
        }

        return jsonResult;
    }

    @Override
    public JsonResult createQinfoNotice(int enterpriseId, QinfoNotice qinfoNotice) {
        JsonResult jsonResult = new JsonResult();
        jsonResult.setStatus("ER");

        qinfoNotice.setEnterpriseId(enterpriseId);

        int retCode = flightCharterDao.createQinfoNotice(qinfoNotice);
        if (retCode > 0) {
            jsonResult.setStatus("OK");
        } else {
            jsonResult.setErrcode(retCode);
            jsonResult.setErrmsg("操作失败");
        }

        return jsonResult;
    }

    @Override
    public JsonResult deleteQinfoNotice(int enterpriseId, int id) {
        JsonResult jsonResult = new JsonResult();
        jsonResult.setStatus("ER");

        int retCode = flightCharterDao.deleteQinfoNotice(enterpriseId, id);
        if (retCode > 0) {
            jsonResult.setStatus("OK");
        } else {
            jsonResult.setErrcode(retCode);
            jsonResult.setErrmsg("操作失败");
        }

        return jsonResult;
    }

    @Override
    public List<QinfoNotice> searchQinfoNotice(int enterpriseId, CommonSearchCriteria sc) {
        return flightCharterDao.searchQinfoNotice(enterpriseId, sc);
    }


    @Override
    @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_DATA_ADMIN})
    public JsonResult saveSubclassInfo(final int enterpriseId, SubclassInfoDto dto) {
        try {
            ValidationUtils.validate(dto);
        } catch (RuntimeException ex) {
            return JsonResult.createJsonResult(-1, ex.getMessage());
        }

        SubclassInfo info = new SubclassInfo();
        BeanUtils.copyProperties(dto, info);

        info.setEnterpriseId(enterpriseId);
        try {
            int retCode = flightCharterDao.saveSubclassInfo(info);
            return JsonResult.createJsonResult(retCode);
        } catch (RuntimeException ex) {
            return JsonResult.createJsonResult(-100, ex.getMessage());
        }
    }

    @Override
    public List<SubclassInfoDto> searchSubclassInfos(int enterpriseId, CommonSearchCriteria sc) {
        if (sc == null) {
            return new ArrayList<>();
        }

        List<SubclassInfo> list = flightCharterDao.searchSubclassInfos(enterpriseId, sc);

        List<SubclassInfoDto> dtos = new ArrayList<>();
        for(SubclassInfo info: list) {
            SubclassInfoDto dto = new SubclassInfoDto();
            BeanUtils.copyProperties(info, dto);

            dtos.add(dto);
        }

        return dtos;
    }

  @Override
  public SubclassInfoDto searchSubclassInfoById(int enterpriseId, int id) {
      SubclassInfo info = flightCharterDao.getSubclassInfoById(id);

      SubclassInfoDto dto = new SubclassInfoDto();
      BeanUtils.copyProperties(info, dto);
      return dto;
  }


  /**
     * 根据tpr指令的内容保存
     */
    @Override
    public JsonResult createTprInfoByContent(final int enterpriseId, final String username,
                                             final String tprContent,
                                             final int deviceId, final Date tprDate) {
        if ((tprContent == null || tprContent.trim().length() <10) && (tprDate == null)) {
            return JsonResult.createJsonResult(-1, "TPR指令内容或TPR日期必须选择提供一个");
        }
        int retCode = 0;
        if (tprContent != null && tprContent.trim().length() > 10) {
            //以TPR内容导入的方式
            doImportTprByContent(enterpriseId, username, tprContent);
        } else {
            //以接口调用的方式
            retCode = doImportTprByApi(enterpriseId, username, deviceId, -1, tprDate);
        }

        JsonResult jsonResult = JsonResult.createJsonResult(retCode);

        if (retCode > 0) {
            jsonResult.setDesc("保存了 " + retCode + " 个票号。");
        }

        return jsonResult;
    }

    @Override
    public void importTprInfoByDate(int enterpriseId, String username, int deviceId, int type3, Date tprDate) {
        //以接口调用的方式
        int retCode = doImportTprByApi(enterpriseId, username, deviceId, type3, tprDate);
        logger.info("{} tickets are saved.", retCode);
    }

    /**
     * 通过内容导入TPR中的信息
     * @return 成功保存的票数
     */
    private int doImportTprByContent(final int enterpriseId, final String username, final String tprContent) {
        //保存TPR结果
        TprInfoDto tprInfo = new TprInfoDto();
        tprInfo.setCmdResult(tprContent);

        int deviceId = 0;
        try {
            deviceId = Integer.parseInt(tprInfo.getDeviceId());
        } catch (Exception ex) {
            //deviceId = 0;
        }

        if (tprInfo.getTotalTicket() > 0 && tprInfo.getTicketCount() == tprInfo.getTotalTicket()) {

        } else if (tprInfo.getTotalTicket() > 0) {
            logger.error("tpr error: total ticket is not equal ticket count.");
        }


        // 不校验总数，能保存多少保存多少

        List<TicketSale> tickets = new ArrayList<>();

        int refundCount = 0;

        for (TprItemDto item : tprInfo.getItems()) {
            if (item.getStatus() == 4) {
                refundCount++;
//                continue; // 退票不保存
            }

            TicketSale ticket = new TicketSale();
            ticket.setEnterpriseId(enterpriseId);


            BeanUtils.copyProperties(item, ticket);

            try {
                ticket.setSellDate(DateUtil.convertToDate(tprInfo.getSellDate()));
            } catch (ParseException e) {
                e.printStackTrace();
            }
            ticket.setDeviceId(deviceId);
            ticket.setOfficeNo(tprInfo.getOfficeNo());
            ticket.setStatus(0);
            ticket.setTicketStatus(item.getStatus());


            tickets.add(ticket);

        }

        final int saved = saveTicketSales(enterpriseId, tickets);



        if (saved > 0 && saved == tprInfo.getTotalTicket()) {
            logger.info("Tpr info have been saved completely.");
        } else {
            logger.error("Tpr info is not saved totally.(" + saved + " < " + tprInfo.getTotalTicket() + ", " + refundCount + ")");
        }

        return saved;
    }

    private int doImportTprByApi(final int enterpriseId, final String username, final int deviceId, final int type3,
                                 final Date tprDate) {
        List<TicketSale> list = etermService.tpr(enterpriseId, username, deviceId, tprDate);

        for(TicketSale ts: list) {
            ts.setType3(type3);
        }

        return saveTicketSales(enterpriseId, list);
    }

    private int saveTicketSales(final int enterpriseId, List<TicketSale> list) {
        for(TicketSale t: list) {
            t.setEnterpriseId(enterpriseId);
        }

        return flightCharterDao.createTicketSales(list);
    }

    @Override
    public List<TicketSaleDto> searchTprs(final int enterpriseId, final int userId,
                                          final String etermUsername,
                                          final String ticketNo, SearchTprCriteria sc) {
        if (sc.getBeginDate() != null && sc.getEndDate() != null && DateUtil.getDaySpan(sc.getEndDate(), sc.getBeginDate()) >= 40) {
            return new ArrayList<>();
        }

        Set<String> roles = userDao.loadUserRoles(userId);
        if (!roles.contains(RoleInfo.ROLE_ADMIN) && !roles.contains(RoleInfo.ROLE_CASHIER)) {
            return new ArrayList<>();
        }

        List<TicketSale> results;

        if (sc.getBeginDate() == null) {
            sc.setBeginDate(DateUtil.addDays(DateUtil.getCurDate(), -365));
        }

        results = flightCharterDao.searchTprs(enterpriseId, ticketNo, sc);


        List<TicketSaleDto> dtos = new ArrayList<>();

        for (TicketSale info : results) {
            TicketSaleDto dto = new TicketSaleDto();
            BeanUtils.copyProperties(info, dto);

            if (!StringUtils.isEmpty(dto.getTicketNo())) {
                String temp = dto.getTicketNo().trim();
                if (temp.length() == 13) {
                    dto.setTenTicketNo(temp.substring(3));
                } else if (temp.length() == 14) {
                    dto.setTenTicketNo(temp.substring(4));
                }
            }

            dtos.add(dto);
        }

        return dtos
                .stream()
                .sorted(Comparator.comparing(TicketSaleDto::getSellDate))
                .sorted(Comparator.comparing(TicketSaleDto::getTenTicketNo))
                .collect(Collectors.toList());
    }

    /**
     * 从excel中导入票号，销售日期，价格，支付备注
     * @param supplierId 供应商名称
     * @param formatNo 格式编号
     */
    @Override
    public int importTicketNo(int enterpriseId, String username, String fileName, int supplierId, int formatNo) {
        int retCode = 0;
        File target = new File(fileName);

        List<TicketSale> tickets = new ArrayList<>();
        try {
            FileInputStream fi = new FileInputStream(target);
            Workbook wb = create(fi);

            if (formatNo == 1) {
                importTicketNoFormat1(enterpriseId, supplierId, tickets, wb);
            } else if (formatNo == 2) {
                importTicketNoFormat2(enterpriseId, username, supplierId, tickets, wb);
            }
        } catch (Exception ex) {
            logger.error(ex.getMessage());

            retCode = -100;
        }

        if (tickets.size() > 0) {
            logger.info("import tickets: " + tickets.size());
            retCode = flightCharterDao.createTicketSales(tickets);
        }

        return retCode;
    }

    private String incTicketNo(final String beginTicketNo, int x) {
        String balanceCode = "", ticketNo="";
        if (beginTicketNo.length() == 13) {
            balanceCode = beginTicketNo.substring(0, 3);
            ticketNo = beginTicketNo.substring(3);
        } else if (beginTicketNo.length() == 14) {
            balanceCode = beginTicketNo.substring(0, 4);
            ticketNo = beginTicketNo.substring(4);
        } else if (beginTicketNo.length() != 10){
            logger.error(beginTicketNo);
            return beginTicketNo;
        }

        long longTicketNo = Long.parseLong(ticketNo) + x;

        return balanceCode + longTicketNo;
    }

    /**
     * 格式1的excel导入
     * 出票日期、开始票号、截止票号、票数、支付金额、支付备注
     * 数据从第二行开始
     */
    private void importTicketNoFormat1(final int enterpriseId, final int supplierId, List<TicketSale> tickets, Workbook wb) {
        Sheet sheet = wb.getSheetAt(0);
        final int rowNum = sheet.getLastRowNum() + 1;
        String saleDate, beginTicketNo;
        int ticketCount;
        double total;
        String payMemo;

        for (int i = 1; i < rowNum; i++) {

            Row row = sheet.getRow(i);
            // 出票日期
            saleDate = row.getCell(0).getStringCellValue().trim();
            if (saleDate.length() != 10) {
                logger.error("importTicketNoFormat1: saleDate = " + saleDate + ".");
                continue;
            }
            //开始票号
            beginTicketNo = row.getCell(1).getStringCellValue().trim();
            // 结束票号
//            endTicketNo = row.getCell(2).getStringCellValue().trim();

            // 票号数量
            Cell cell = row.getCell(3);
            if (cell.getCellType() == CellType.STRING) {
                ticketCount = Integer.parseInt(cell.getStringCellValue().trim());
            } else if (cell.getCellType() == CellType.NUMERIC) {
                ticketCount = (int) cell.getNumericCellValue();
            } else {
                logger.info("cell[3] type is not expected.");
                continue;
            }

            // 支付价格
            cell = row.getCell(4);
            if (cell.getCellType() == CellType.STRING) {
                total = Double.parseDouble(cell.getStringCellValue().trim());
            } else if (cell.getCellType() == CellType.NUMERIC) {
                total = cell.getNumericCellValue();
            } else {
                logger.info("cell[4] type is not expected.");
                continue;
            }

            //支付备注
            cell = row.getCell(5);
            if (cell.getCellType() == CellType.STRING) {
                payMemo = cell.getStringCellValue().trim();
            } else {
                logger.info("cell[5] type is not expected.");
                continue;
            }


            for (int x = 0; x < ticketCount; x++) {
                TicketSale ticket = new TicketSale();
                ticket.setEnterpriseId(enterpriseId);
                ticket.setPayMemo(payMemo);
                try {
                    ticket.setSellDate(DateUtil.convertToDate(saleDate));
                    if (supplierId  > 0) {
                        Supplier supplier = enterpriseDao.getSupplierById(supplierId);
                        ticket.setSupplier(supplier);
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                ticket.setBottomPrice(total / ticketCount);
                if (x == 0) {
                    ticket.setTicketNo(beginTicketNo);
                } else {
                    ticket.setTicketNo(incTicketNo(beginTicketNo, x));
                }
                tickets.add(ticket);
            }
        }
    }

    /**
     * 格式2的excel导入
     * 票号(校验13位或14位)、订单编号，PNR，航班号（可能有多个航班号）、应付款(为负数的不导入）、出票日期
     * 数据从第二行开始
     */
    private void importTicketNoFormat2(final int enterpriseId, final String username, final int supplierId, List<TicketSale> tickets, Workbook wb) {
        Sheet sheet = wb.getSheetAt(0);
        final int rowNum = sheet.getLastRowNum() + 1;
        String saleDate, beginTicketNo, pnrNo, psgName;
        double total;
        Cell cell;

        for (int i = 1; i < rowNum; i++) {
            beginTicketNo = "";

            Row row = sheet.getRow(i);

            //票号
            beginTicketNo = row.getCell(0).getStringCellValue().trim();
            //乘机人
            psgName = row.getCell(0).getStringCellValue().trim();
            //pnr
            pnrNo = row.getCell(2).getStringCellValue().trim();
            //flight no
//            flightNo = row.getCell(3).getStringCellValue().trim();

            // 应付款
            cell = row.getCell(4);
            if (cell.getCellType() == CellType.STRING) {
                total = Double.parseDouble(cell.getStringCellValue().trim());
            } else if (cell.getCellType() == CellType.NUMERIC) {
                total = cell.getNumericCellValue();
            } else {
                logger.info("cell[4] type is not expected.");
                continue;
            }

            if (total < 0) {
                logger.info(beginTicketNo + ", " + total + ": ignored.");
                continue;
            }

            saleDate = "";
            cell = row.getCell(5);
            if (cell.getCellType() == CellType.STRING) {
                // 出票日期
                saleDate = cell.getStringCellValue().trim();
            } else if (cell.getCellType() == CellType.NUMERIC) {
                saleDate = parseExcel(cell);
            } else {
                logger.info("cell[5] type is not expected.");
                continue;
            }

            if (saleDate == null || saleDate.trim().length() != 10) {
                logger.error("importTicketNoFormat2: saleDate = " + saleDate + ".");
                continue;
            }


            if (!FlightTicketUtil.verifyTicketNo(beginTicketNo)) {
                logger.error(beginTicketNo + " is not correct");
                continue;
            }

            if (beginTicketNo.length() == 13) {
                beginTicketNo = beginTicketNo.substring(0, 3) + "-" + beginTicketNo.substring(3);
            }


            TicketSale ticket = new TicketSale();
            ticket.setEnterpriseId(enterpriseId);
            ticket.setTicketNo(beginTicketNo);
            ticket.setPnrNo(pnrNo);
            ticket.setOperator(username);
            ticket.setPsgName(psgName);
            try {
                ticket.setSellDate(DateUtil.convertToDate(saleDate));
            } catch (ParseException e) {
                e.printStackTrace();
            }
            if (supplierId > 0) {
                Supplier supplier = enterpriseDao.getSupplierById(supplierId);
                ticket.setSupplier(supplier);
            }
            ticket.setBottomPrice(total);

            tickets.add(ticket);

        }
    }


    private String parseExcel(Cell cell) {
        String result;
        switch (cell.getCellType()) {
            case NUMERIC:
                if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) {
                    SimpleDateFormat sdf = null;
                    if (cell.getCellStyle().getDataFormat() == HSSFDataFormat
                            .getBuiltinFormat("h:mm")) {
                        sdf = new SimpleDateFormat("HH:mm");
                    } else {// 日期
                        sdf = new SimpleDateFormat("yyyy-MM-dd");
                    }
                    Date date = cell.getDateCellValue();
                    result = sdf.format(date);
                } else if (cell.getCellStyle().getDataFormat() == 58) {
                    // 处理自定义日期格式：m月d日(通过判断单元格的格式id解决，id的值是58)
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                    double value = cell.getNumericCellValue();
                    Date date = org.apache.poi.ss.usermodel.DateUtil
                            .getJavaDate(value);
                    result = sdf.format(date);
                } else {
                    double value = cell.getNumericCellValue();
                    CellStyle style = cell.getCellStyle();
                    DecimalFormat format = new DecimalFormat();
                    String temp = style.getDataFormatString();
                    // 单元格设置成常规
                    if ("General".equals(temp)) {
                        format.applyPattern("#");
                    }
                    result = format.format(value);
                }
                break;
            case STRING:
                result = cell.getRichStringCellValue().toString();
                break;
            default:
                result = "";
                break;
        }
        return result;
    }



}
